package com.qf.utils;


import io.jsonwebtoken.Claims;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.annotation.Resource;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;


/**
 * 前端请求头中获取token并认证
 *
 * doFilterInternal 是 Spring Security 中 OncePerRequestFilter 抽象类的核心方法，
 * 用于实现自定义的过滤器逻辑，且保证每个请求只会被过滤一次（避免因 DispatcherServlet 转发等场景导致的重复过滤）。
 * 在 JWT 认证场景中，通常会自定义一个继承 OncePerRequestFilter 的过滤器，
 * 并重写 doFilterInternal 方法来实现 JWT 令牌的验证逻辑。
 *
 */

@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {

    @Resource
    private JwtUtils jwtUtils;
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        // 调用JwtUtils中的getToken方法获取前端发送token
        String token = jwtUtils.getToken(request);
        System.out.println("拿到前端token = " + token);
        // 判断token信息是否存在，是否已经存在于上下文中
        if(!ObjectUtils.isEmpty(token) && SecurityContextHolder.getContext().getAuthentication() == null) {

            //验证token，如果验证失败则抛出异常
            jwtUtils.validateToken(token);
            //如果哦验证成功，刷新令牌时间
            jwtUtils.refreshToken(token);

            /**
             * 如果token不为空,或者认证信息未放入上下文，解析token
             */


            Claims claims = jwtUtils.parseToken(token);
            //从claims中获取角色权限信息
            List<String> perms = claims.get("perms", List.class);
            //将权限信息拼接成字符串
            if (perms!=null && !perms.isEmpty()) {
                String permissionString = String.join(",", perms);
                //存储claims中用户名
                String username = claims.getSubject();
                //将用户名放入Authentication查找密码
                UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(username, null, AuthorityUtils.commaSeparatedStringToAuthorityList(permissionString));
                usernamePasswordAuthenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                //将认证信息放入上下文
                SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
            }





        }

        /**
         * 如果token为空,或者认证信息已经放入上下文,则直接放行
         */


        filterChain.doFilter(request, response);


    }





}
